#include "Sha1.h"
#include <string.h>

static unsigned int FromBigEndian(unsigned int v)
{
	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) |
		   ((v & 0xff000000) >> 24);
}

static void WriteBigEndian64(unsigned char *p, unsigned int v)
{
	unsigned char t;
	memset(p, 0, 8);
	memcpy(p, &v, 4);
	int i=0;
	for(i = 0; i < 4; i++)
	{
		t = p[i];
		p[i] = p[7 - i];
		p[7 - i] = t;
	}
}

static unsigned int LeftRol(unsigned int v, int n)
{
	return (v << n) | (v >> (32 - n));
}

unsigned char * SHA1(const unsigned char* data, size_t dataLen, unsigned char* md)
{
	unsigned char* pbytes = (unsigned char*)data;
	unsigned int nbyte = dataLen;
	
	static unsigned int words[80];
	unsigned int H[5] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
	unsigned int a, b, c, d, e, f, k, temp, bitlen[2], word;
	unsigned int i, j, index, p1, p2, maxlen;
	unsigned char spec[4] = {0};
	i = nbyte % 4;

	p1 = nbyte - i;
	spec[i] = 1 << 7;
	while (i--)
	{
		spec[i] = pbytes[p1 + i];
	}

	maxlen = (nbyte + 1) % 64;
	if(maxlen <= 56)
	{
		maxlen = (nbyte + 1) - maxlen + 64;
	}
	else
	{
		maxlen = (nbyte + 1) - maxlen + 128;
	}
	p2= maxlen - 8;
 	WriteBigEndian64((unsigned char*)bitlen, nbyte * 8);

	for(j = 0; j < maxlen; j += 64)
	{
		a = H[0];
		b = H[1];
		c = H[2];
		d = H[3];
		e = H[4];
		for(i = 0; i < 80; i++)
		{
			if(i < 16)
			{
				index = j + (i << 2);
				if(index < p1)
				{
					word = *((unsigned int*)(pbytes + index));
				}
				else if(index == p1)
				{
					word = *(unsigned int*)spec;
				}
				else if(index < p2)
				{
					word = 0;
				}
				else 
				{
					word = (index < maxlen - 4) ? bitlen[0] : bitlen[1];
				}
				words[i] = FromBigEndian(word);
			}
			else 
			{
				words[i] = LeftRol(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1);
			}
			if(i < 20)
			{
				f = (b & c) | ((~b) & d);
				k = 0x5A827999;
			}
			else if (i < 40)
			{
				f=b ^ c ^ d;
				k = 0x6ED9EBA1;
			}
			else if (i < 60)
			{
				f = (b & c) | (b & d) | (c & d);
				k = 0x8F1BBCDC;
			}
			else 
			{
				f = b ^ c ^ d;
				k = 0xCA62C1D6;
			}
			temp = LeftRol(a, 5) + f + e + k + words[i];
			e = d;
			d = c;
			c = LeftRol(b, 30);
			b = a;
			a = temp;
		}
		H[0] += a;
		H[1] += b;
		H[2] += c;
		H[3] += d;
		H[4] += e;

	}
	int ct = 0;
	for (i = 0; i < 5; i++)
	{
		unsigned char buf[4] = {0};
		memcpy(buf, &(H[i]), 4);
		for (int r = 3; r >= 0; r--)
		{
			md[ct] = buf[r];
			ct++;
		}
	}

	return md;
}


